//---------------------------------------------------------------------------------
// Copyright (c) 2008 VoiceLynx Project
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not be
//        misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//        distribution.
//---------------------------------------------------------------------------------

#include "VLUserSettings.h"


/////////////////////////// Loose Functions ///////////////////////////
void enumerateGroups(wxConfigBase &config, wxArrayString &stringArray)
{
  wxString str;
  long dummy;

  bool hasMoreEntries = config.GetFirstGroup(str, dummy);
  while (hasMoreEntries) 
  {
    stringArray.Add(str);

    hasMoreEntries = config.GetNextGroup(str, dummy);
  }
}

template <class T>
void RemoveMissingEntries(wxConfigBase &config, std::map<wxString, T> &map)
{
  wxArrayString serverNamesToDelete;
  enumerateGroups(config, serverNamesToDelete);

  // Iterate through our local map, remove what is in the map from the list
  for (std::map<wxString, T>::iterator iter = map.begin(); 
    iter != map.end(); ++iter)
  {
    int indexToDelete = serverNamesToDelete.Index(iter->first, true);

    if (indexToDelete != wxNOT_FOUND)
    {
      serverNamesToDelete.RemoveAt(indexToDelete);
    }
  }

  // Now, delete any leftover entries
  for (wxArrayString::iterator iter = serverNamesToDelete.begin(); 
    iter != serverNamesToDelete.end(); ++iter)
  {
    config.DeleteGroup(*iter);
  }
}

////////////////////////// ServerSettings //////////////////////////////
void VLServerSettings::getServerNames(wxArrayString &names)
{
  for (VLServerSettingsEntryMap::iterator iter = mServerMap.begin(); 
    iter != mServerMap.end(); ++iter)
  {
    names.push_back(iter->first);
  }
}

bool VLServerSettings::getServer(const wxString &name, VLServerSettingsEntry &server)
{
  bool returnVal = false;

  VLServerSettingsEntryMap::iterator iter = mServerMap.find(name);
  if (iter != mServerMap.end())
  {
    server = iter->second;
    returnVal = true;
  }

  return returnVal;
}

void VLServerSettings::setServer(const VLServerSettingsEntry &server)
{
  // The server's key is always the server's name
  mServerMap[server.name] = server;
}

void VLServerSettings::deleteServer(const wxString &name)
{
  VLServerSettingsEntryMap::iterator iter = mServerMap.find(name);
  if (iter != mServerMap.end())
  {
    mServerMap.erase(iter);
  }
}

void VLServerSettings::write(wxConfigBase &config)
{
  // Store the old path
  wxString oldPath = config.GetPath();

  // Descend to the servers group
  config.SetPath(VL_CONFIG_PATH_SERVERS);

  // Remove from the config any data that is not in the map
  RemoveMissingEntries(config, mServerMap);

  // Push all data from the map into the config
  for (VLServerSettingsEntryMap::iterator iter = mServerMap.begin(); 
    iter != mServerMap.end(); ++iter)
  {
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_NAME, iter->second.name);
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_HOST, iter->second.host);
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_PORT, iter->second.port);
  }

  // Set the old path
  config.SetPath(oldPath);
}

void VLServerSettings::read(wxConfigBase &config)
{
  // Clear out old state
  mServerMap.clear();
  
  // Store the old path
  wxString oldPath = config.GetPath();

  // Descend to the servers group
  config.SetPath(VL_CONFIG_PATH_SERVERS);

  // Get all groups (each server is a subgroup)
  wxArrayString serverNames;
  enumerateGroups(config, serverNames);

  // For every group, add a new entry to the server map
  for (wxArrayString::iterator iter = serverNames.begin(); 
    iter != serverNames.end(); ++iter)
  {
    VLServerSettingsEntry serverInfo;

    serverInfo.name = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_NAME, VL_CONFIG_EMPTY_STRING);
    serverInfo.host = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_HOST, VL_CONFIG_EMPTY_STRING);
    serverInfo.port = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_SERVER_PORT, VL_DEFAULT_PORT);

    mServerMap[serverInfo.name] = serverInfo;
  }

  // Set the old path
  config.SetPath(oldPath);
}

/////////////////////// Profile Settings ////////////////////////////////
void VLProfileSettings::getProfileNames(wxArrayString &names)
{
  for (VLProfileSettingsEntryMap::iterator iter = mProfileMap.begin(); 
    iter != mProfileMap.end(); ++iter)
  {
    names.push_back(iter->first);
  }
}

bool VLProfileSettings::getProfile(const wxString &name, VLProfileSettingsEntry &profile)
{
  bool returnVal = false;

  VLProfileSettingsEntryMap::iterator iter = mProfileMap.find(name);

  if (iter != mProfileMap.end())
  {
    profile = iter->second;
    returnVal = true;
  }

  return returnVal;
}

void VLProfileSettings::setProfile(const VLProfileSettingsEntry &profile)
{
  mProfileMap[profile.name] = profile;
}

void VLProfileSettings::deleteProfile(const wxString &name)
{
  VLProfileSettingsEntryMap::iterator iter = mProfileMap.find(name);
  if (iter != mProfileMap.end())
  {
    mProfileMap.erase(iter);
  }
}

void VLProfileSettings::write(wxConfigBase &config)
{
  // Store the old path
  wxString oldPath = config.GetPath();

  // Descend to the servers group
  config.SetPath(VL_CONFIG_PATH_PROFILES);

  // Remove from the config any data that is not in the map
  RemoveMissingEntries(config, mProfileMap);

  // Push all data from the map into the config
  for (VLProfileSettingsEntryMap::iterator iter = mProfileMap.begin(); 
    iter != mProfileMap.end(); ++iter)
  {
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_NAME, iter->second.name);
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_USERNAME, iter->second.username);
    config.Write(iter->first + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_PASSWORD, iter->second.password);
  }

  // Set the old path
  config.SetPath(oldPath);
}

void VLProfileSettings::read(wxConfigBase &config)
{
  // Clear out old state
  mProfileMap.clear();

  // Store the old path
  wxString oldPath = config.GetPath();

  // Descend to the servers group
  config.SetPath(VL_CONFIG_PATH_PROFILES);

  // Get all groups (each server is a subgroup)
  wxArrayString serverNames;
  enumerateGroups(config, serverNames);

  // For every group, add a new entry to the server list
  for (wxArrayString::iterator iter = serverNames.begin(); 
    iter != serverNames.end(); ++iter)
  {
    VLProfileSettingsEntry profileInfo;

    profileInfo.name     = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_NAME, VL_CONFIG_EMPTY_STRING);
    profileInfo.username = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_USERNAME, VL_CONFIG_EMPTY_STRING);
    profileInfo.password = config.Read(*iter + VL_CONFIG_PATH_SEPERATOR + VL_CONFIG_KEY_PROFILE_PASSWORD, VL_CONFIG_EMPTY_STRING);

    mProfileMap[profileInfo.name] = profileInfo;
  }

  // Set the old path
  config.SetPath(oldPath);
}